package org.front.server.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.front.server.business.DistributeurBusiness;
import org.front.shared.data.Compartiment;
import org.front.shared.data.Distributeur;
import org.front.shared.data.Produit;
import org.front.shared.data.Transaction;
import org.springframework.jdbc.InvalidResultSetAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;

public class DistributeurDaoImpl implements DistributeurDao {

	private static final Logger LOG = Logger.getLogger(DistributeurBusiness.class);

	private JdbcTemplate jdbcTemplate;

	private static final String SELECT_DISTRIBUTEUR = "SELECT numero, model, marque, ligne, colonne, montantcaisse FROM distributeur";
	
	private static final String UPDATE_DISTRIBUTEUR = "UPDATE distributeur SET montantcaisse = ?";

	private static final String SELECT_LIST_PRODUIT = "SELECT code, description, prix FROM produit ORDER BY code";

	private static final String SELECT_PRODUIT = "SELECT code, description, prix FROM produit WHERE code = ?";

	private static final String SELECT_LIST_COMPARTIMENT = "SELECT numero, codeproduit, quantite FROM compartiment";

	private static final String SELECT_LIST_TRANSACTION = "SELECT date, codeproduit, montant FROM transaction ORDER BY date DESC";
	
	private static final String SELECT_LIST_TRANSACTION_PAR_DATE = "SELECT date, codeproduit, montant FROM transaction WHERE date >= ? AND date <= ? ORDER BY date DESC";

	private static final String INSERT_TRANSACTION = "INSERT INTO transaction VALUES (?, ?, ?)";

	private static final String UPDATE_COMPARTIMENT = "UPDATE compartiment SET quantite = ? WHERE numero = ?";

	private static final String DELETE_COMPARTIMENT = "DELETE FROM compartiment WHERE numero = ?";

	private static final String INSERT_COMPARTIMENT = "INSERT INTO compartiment VALUES (?, ?, ?)";

	@Override
	public Distributeur getDistributeurInfo() throws Exception {
		try {
			Distributeur distributeur = new Distributeur();

			SqlRowSet rs = jdbcTemplate.queryForRowSet(SELECT_DISTRIBUTEUR);
			if (rs.next()) {
				distributeur.setNumero(rs.getString("numero"));
				distributeur.setModel(rs.getString("model"));
				distributeur.setMarque(rs.getString("marque"));
				distributeur.setNombreLigne(rs.getInt("ligne"));
				distributeur.setNombreColonne(rs.getInt("colonne"));
				distributeur.setMontantCaisse(rs.getDouble("montantcaisse"));
			}

			return distributeur;
		} catch (Exception exception) {
			LOG.error("Erreur dans la recuperation des infos du distributeur", exception);
			throw exception;
		}
	}
	

	@Override
	public void modifierMontantCaisse(double montant) throws Exception {
		try {
			this.jdbcTemplate.update(UPDATE_DISTRIBUTEUR, new Object[] {montant});
		} catch (Exception exception) {
			LOG.error("Erreur dans la modification du montant de la caisse ", exception);
			throw exception;
		}
	}

	@Override
	public List<Produit> getListProduits() throws Exception {
		try {
			List<Produit> listProduits = new ArrayList<Produit>();

			SqlRowSet rs = jdbcTemplate.queryForRowSet(SELECT_LIST_PRODUIT);
			while (rs.next()) {
				listProduits.add(getProduit(rs));
			}

			return listProduits;
		} catch (Exception exception) {
			LOG.error("Erreur dans la recuperation de la liste des produits", exception);
			throw exception;
		}
	}

	private Produit getProduit(SqlRowSet rs) {
		Produit produit = new Produit();
		produit.setCode(rs.getString("code"));
		produit.setDescription(rs.getString("description"));
		produit.setPrix(rs.getDouble("prix"));
		return produit;
	}

	@Override
	public Map<String, Compartiment> getMapCompartiment() throws Exception {
		try {

			Map<String, Compartiment> mapCompartiments = new HashMap<String, Compartiment>();

			SqlRowSet rs = jdbcTemplate.queryForRowSet(SELECT_LIST_COMPARTIMENT);
			while (rs.next()) {
				Compartiment compartiment = new Compartiment();
				compartiment.setNumero(rs.getString("numero"));
				compartiment.setProduit(getProduit(rs.getString("codeproduit")));
				compartiment.setQuantite(rs.getInt("quantite"));
				mapCompartiments.put(compartiment.getNumero(), compartiment);
			}

			return mapCompartiments;
		} catch (Exception exception) {
			LOG.error("Erreur dans la recuperation de la map des compartiments", exception);
			throw exception;
		}
	}

	@Override
	public Produit getProduit(String codeProduit) throws Exception {
		try {
			Produit produit = new Produit();

			SqlRowSet rs = jdbcTemplate.queryForRowSet(SELECT_PRODUIT, new Object[] { codeProduit });
			if (rs.next()) {
				produit = getProduit(rs);
			}
			return produit;
		} catch (Exception exception) {
			LOG.error("Erreur dans la recuperation des infos du distributeur", exception);
			throw exception;
		}
	}

	@Override
	public List<Transaction> getlistTransactions() throws Exception {
		try {
			List<Transaction> listTransactions = new ArrayList<Transaction>();

			SqlRowSet rs = jdbcTemplate.queryForRowSet(SELECT_LIST_TRANSACTION);
			while (rs.next()) {
				listTransactions.add(getTransaction(rs));				
			}

			return listTransactions;
		} catch (Exception exception) {
			LOG.error("Erreur dans la recuperation de la lite des transactions", exception);
			throw exception;
		}
	}
	
	@Override
	public List<Transaction> getlistTransactions(Date dateDebut, Date dateFin) throws Exception {
		try {
			List<Transaction> listTransactions = new ArrayList<Transaction>();

			SqlRowSet rs = jdbcTemplate.queryForRowSet(SELECT_LIST_TRANSACTION_PAR_DATE, new Object[] { dateDebut, dateFin});
			while (rs.next()) {
				listTransactions.add(getTransaction(rs));				
			}
			return listTransactions;
		} catch (Exception exception) {
			LOG.error("Erreur dans la recuperation de la lite des transactions", exception);
			throw exception;
		}
	}
	
	private Transaction getTransaction(SqlRowSet rs) throws InvalidResultSetAccessException, Exception {
		Transaction transaction = new Transaction();
		transaction.setDate(new Date(rs.getDate("date").getTime()));
		Produit produit = new Produit();
		produit.setCode(rs.getString("codeproduit"));
		transaction.setProduit(produit);
		transaction.setMontant(rs.getDouble("montant"));		
		return transaction;
	}


	@Override
	public void ajouterTransaction(Transaction transaction) throws Exception {
		try {
			this.jdbcTemplate.update(INSERT_TRANSACTION, new Object[] { transaction.getProduit().getCode(), transaction.getMontant(), transaction.getDate() });
		} catch (Exception exception) {
			LOG.error("Erreur dans l'insetion d'une transaction", exception);
			throw exception;
		}
	}


	@Override
	public void modifierCompartiment(Compartiment compartiment, int quantite) throws Exception {
		try {
			this.jdbcTemplate.update(UPDATE_COMPARTIMENT, new Object[] { quantite, compartiment.getNumero() });
		} catch (Exception exception) {
			LOG.error("Erreur dans de la mise ajour du compartiment", exception);
			throw exception;
		}
	}

	@Override
	public void supprimerProduitCompartiment(Compartiment compartiment) throws Exception {
		try {
			this.jdbcTemplate.update(DELETE_COMPARTIMENT, new Object[] { compartiment.getNumero() });
		} catch (Exception exception) {
			LOG.error("Erreur dans de la suppresion du compartiment", exception);
			throw exception;
		}
	}

	@Override
	public void ajouterCompartiment(Compartiment compartiment, Produit produit, int quantite) throws Exception {
		try {
			this.jdbcTemplate.update(INSERT_COMPARTIMENT, new Object[] { compartiment.getNumero(), produit.getCode(), quantite });
		} catch (Exception exception) {
			LOG.error("Erreur dans l'ajout du compartiment", exception);
			throw exception;
		}
	}
	
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
}
